import type { AxiosInstance, AxiosRequestConfig, AxiosResponse, InternalAxiosRequestConfig } from "axios";
import axios from "axios";
import { toast } from "sonner";
import { checkStatus } from "@/utils";

const _config: AxiosInstance = axios.create({
  baseURL: import.meta.env.VITE_APP_BASE_URL,
  timeout: import.meta.env.VITE_APP_AXIOS_TIMEOUT
});

class RequestHttp {
  #requestInstance: AxiosInstance;
  constructor(_config: AxiosInstance) {
    this.#requestInstance = _config;

    this.#requestInstance.interceptors.request.use(
      (config: InternalAxiosRequestConfig) => {
        return config;
      },
      (error) => Promise.reject(error)
    );

    this.#requestInstance.interceptors.response.use(
      (response: AxiosResponse) => {
        const code = Number.parseInt(response.data.code || response.data.status) || 200;
        const msg = response.data.msg || response.data.message;
        if (code === 401 || code === 403) {
          toast.error(msg);
          return Promise.reject(msg);
        }
        if (code > 200 || code < 200) {
          toast.error(msg);
          return Promise.reject(msg);
        }
        return response.data;
      },
      (error) => {
        const { response } = error;
        // 请求超时 && 网络错误单独判断，没有 response
        if (error.message.includes("Network Error")) toast.error("网络错误！请您稍后重试");
        if (error.message.includes("timeout")) toast.error("请求超时！请您稍后重试");
        // 根据服务器响应的错误状态码，做不同的处理
        if (response) checkStatus(response.status);
        return Promise.reject(error);
      }
    );
  }

  get<T = any>(url: string, params: Record<string, any> = {}, config: AxiosRequestConfig = {}): Promise<T> {
    return this.#requestInstance.get(url, { params, ...config });
  }

  delete<T = any>(url: string, params: Record<string, any> = {}, config: AxiosRequestConfig = {}): Promise<T> {
    return this.#requestInstance.delete(url, { params, ...config });
  }

  post<T = any>(url: string, data: Record<string, any> = {}, config: AxiosRequestConfig = {}): Promise<T> {
    return this.#requestInstance.post(url, data, config);
  }

  put<T = any>(url: string, data: Record<string, any> = {}, config: AxiosRequestConfig = {}): Promise<T> {
    return this.#requestInstance.put(url, data, config);
  }
}

export const Request = new RequestHttp(_config);
